home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / sgml / msdos / sgml07 / sgmldecl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-27  |  38.9 KB  |  1,607 lines

  1. /* sgmldecl.c -
  2.    SGML declaration parsing.
  3.  
  4.    Written by James Clark (jjc@jclark.com).
  5. */
  6.  
  7. #include "sgmlincl.h"
  8.  
  9. /* Symbolic names for the error numbers that are be generated only by
  10. this module. */
  11.  
  12. #define E_COLON 163
  13. #define E_SIGNIFICANT 164
  14. #define E_BADLIT 165
  15. #define E_SCOPE 166
  16. #define E_XNUM 167
  17. #define E_BADVERSION 168
  18. #define E_NAMING 169
  19. #define E_XNMLIT 170
  20. #define E_CHARDESC 171
  21. #define E_CHARDUP 172
  22. #define E_CHARRANGE 173
  23. #define E_7BIT 174
  24. #define E_CHARMISSING 175
  25. #define E_SHUNNED 176
  26. #define E_NONSGML 177
  27. #define E_CAPSET 178
  28. #define E_CAPMISSING 179
  29. #define E_SYNTAX 180
  30. #define E_CHARNUM 181
  31. #define E_SWITCHES 182
  32. #define E_INSTANCE 183
  33. #define E_ZEROFEATURE 184
  34. #define E_YESNO 185
  35. #define E_CAPACITY 186
  36. #define E_NOTSUPPORTED 187
  37. #define E_FORMAL 189
  38. #define E_BADCLASS 190
  39. #define E_MUSTBENON 191
  40. #define E_BADBASECHAR 199
  41. #define E_SYNREFUNUSED 200
  42. #define E_SYNREFUNDESC 201
  43. #define E_SYNREFUNKNOWN 202
  44. #define E_SYNREFUNKNOWNSET 203
  45. #define E_FUNDUP 204
  46. #define E_BADFUN 205
  47. #define E_FUNCHAR 206
  48. #define E_GENDELIM 207
  49. #define E_SRDELIM 208
  50. #define E_BADKEY 209
  51. #define E_BADQUANTITY 210
  52. #define E_BADNAME 211
  53. #define E_REFNAME 212
  54. #define E_DUPNAME 213
  55. #define E_QUANTITY 214
  56. #define E_QTOOBIG 215
  57.  
  58. #define CANON_NONSGML 255  /* Canonical non-SGML character. */
  59. #define CANON_DATACHAR 254 /* Canonical DATACHAR. */
  60. #define SUCCESS 1
  61. #define FAIL 0
  62. #define SIZEOF(v) (sizeof(v)/sizeof(v[0]))
  63. #define matches(tok, str) (ustrcmp((tok)+1, (str)) == 0)
  64.  
  65. static UNCH standard[] = "ISO 8879-1986";
  66.  
  67. #define REFERENCE_SYNTAX "ISO 8879-1986//SYNTAX Reference//EN"
  68. #define CORE_SYNTAX "ISO 8879-1986//SYNTAX Core//EN"
  69.  
  70. static UNCH (*newkey)[REFNAMELEN+1] = 0;
  71.  
  72. struct pmap {
  73.      char *name;
  74.      UNIV value;
  75. };
  76.  
  77. /* The reference capacity set. */
  78. #define REFCAPSET \
  79. { 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, \
  80. 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L, 35000L }
  81.  
  82. long refcapset[NCAPACITY] = REFCAPSET;
  83.  
  84. /* A pmap of known capacity sets. */
  85.  
  86. static struct pmap capset_map[] = {
  87.      "ISO 8879-1986//CAPACITY Reference//EN", (UNIV)refcapset,
  88.      0
  89. };
  90.  
  91. /* Table of capacity names.  Must match enum capacity. */
  92.  
  93. char *captab[] = {
  94.      "TOTALCAP",
  95.      "ENTCAP",
  96.      "ENTCHCAP",
  97.      "ELEMCAP",
  98.      "GRPCAP",
  99.      "EXGRPCAP",
  100.      "EXNMCAP",
  101.      "ATTCAP",
  102.      "ATTCHCAP",
  103.      "AVGRPCAP",
  104.      "NOTCAP",
  105.      "NOTCHCAP",
  106.      "IDCAP",
  107.      "IDREFCAP",
  108.      "MAPCAP",
  109.      "LKSETCAP",
  110.      "LKNMCAP",
  111. };
  112.  
  113. /* The default SGML declaration. */
  114. #define MAXNUMBER 99999999L
  115.  
  116. /* Reference quantity set */
  117.  
  118. #define REFATTCNT 40
  119. #define REFATTSPLEN 960
  120. #define REFBSEQLEN 960
  121. #define REFDTAGLEN 16
  122. #define REFDTEMPLEN 16
  123. #define REFENTLVL 16
  124. #define REFGRPCNT 32
  125. #define REFGRPGTCNT 96
  126. #define REFGRPLVL 16
  127. #define REFLITLEN 240
  128. #define REFNORMSEP 2
  129. #define REFPILEN 240
  130. #define REFTAGLEN 960
  131. #define REFTAGLVL 24
  132.  
  133. #define ALLOC_MAX 65534
  134.  
  135. #define BIGINT 30000
  136.  
  137. #define MAXATTCNT ((ALLOC_MAX/sizeof(struct ad)) - 2)
  138. #define MAXATTSPLEN BIGINT
  139. #define MAXBSEQLEN BIGINT
  140. #define MAXDTAGLEN 16
  141. #define MAXDTEMPLEN 16
  142. #define MAXENTLVL ((ALLOC_MAX/sizeof(struct source)) - 1)
  143. #define MAXGRPCNT MAXGRPGTCNT
  144. /* Must be between 96 and 253 */
  145. #define MAXGRPGTCNT 253
  146. #define MAXGRPLVL MAXGRPGTCNT
  147. #define MAXLITLEN BIGINT
  148. /* This guarantees that NAMELEN < LITLEN (ie there's always space for a name
  149. in a buffer intended for a literal.) */
  150. #define MAXNAMELEN (REFLITLEN - 1)
  151. #define MAXNORMSEP 2
  152. #define MAXPILEN BIGINT
  153. #define MAXTAGLEN BIGINT
  154. #define MAXTAGLVL ((ALLOC_MAX/sizeof(struct tag)) - 1)
  155.  
  156. /* Table of quantity names.  Must match enum quantity. */
  157.  
  158. static char *quantity_names[] = {
  159.     "ATTCNT",   
  160.     "ATTSPLEN", 
  161.     "BSEQLEN",  
  162.     "DTAGLEN",  
  163.     "DTEMPLEN", 
  164.     "ENTLVL",   
  165.     "GRPCNT",   
  166.     "GRPGTCNT", 
  167.     "GRPLVL",   
  168.     "LITLEN",   
  169.     "NAMELEN",  
  170.     "NORMSEP",  
  171.     "PILEN",    
  172.     "TAGLEN",   
  173.     "TAGLVL",    
  174. };
  175.  
  176. static int max_quantity[] = {
  177.     MAXATTCNT,
  178.     MAXATTSPLEN,
  179.     MAXBSEQLEN,
  180.     MAXDTAGLEN,
  181.     MAXDTEMPLEN,
  182.     MAXENTLVL,
  183.     MAXGRPCNT,
  184.     MAXGRPGTCNT,
  185.     MAXGRPLVL,
  186.     MAXLITLEN,
  187.     MAXNAMELEN,
  188.     MAXNORMSEP,
  189.     MAXPILEN,
  190.     MAXTAGLEN,
  191.     MAXTAGLVL,
  192. };
  193.  
  194. static char *quantity_changed;
  195.  
  196. /* Non-zero means the APPINFO parameter was not NONE. */
  197. static int appinfosw = 0;
  198. UNCH appinfo[REFLITLEN+1];
  199.  
  200. struct sgmldecl sd = {
  201.      REFCAPSET,            /* capacity */
  202. #ifdef SUPPORT_SUBDOC
  203.      MAXNUMBER,            /* subdoc */
  204. #else /* not SUPPORT_SUBDOC */
  205.      0,                /* subdoc */
  206. #endif /* not SUPPORT_SUBDOC */
  207.      1,                /* formal */
  208.      1,                /* omittag */
  209.      1,                /* shorttag */
  210.      1,                /* shortref */
  211.      { 1, 0 },            /* general/entity name case translation */
  212.      {                /* reference quantity set */
  213.       REFATTCNT,
  214.       REFATTSPLEN,
  215.       REFBSEQLEN,
  216.       REFDTAGLEN,
  217.       REFDTEMPLEN,
  218.       REFENTLVL,
  219.       REFGRPCNT,
  220.       REFGRPGTCNT,
  221.       REFGRPLVL,
  222.       REFLITLEN,
  223.       REFNAMELEN,
  224.       REFNORMSEP,
  225.       REFPILEN,
  226.       REFTAGLEN,
  227.       REFTAGLVL,
  228.      },
  229. };
  230.  
  231. #define UNUSED -1
  232. #define UNKNOWN -2
  233. #define UNDESC -3
  234. #define UNKNOWN_SET -4
  235.  
  236. static int asciicharset[] = {
  237. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
  238. 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
  239. 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
  240. 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
  241. 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  242. 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
  243. 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
  244. 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
  245. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  246. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  247. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  248. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  249. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  250. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  251. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  252. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  253. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  254. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  255. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  256. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  257. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  258. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  259. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  260. UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
  261. };
  262.  
  263. static struct pmap charset_map[] = {
  264.      "ESC 2/5 4/0", (UNIV)asciicharset, /* ISO 646 IRV */
  265.      "ESC 2/8 4/2", (UNIV)asciicharset, /* ISO Registration Number 6, ASCII */
  266.      0
  267. };
  268.  
  269. #define DUMMY_CHARSET "-//dummy//CHARSET dummy//ESC 0/0 0/0"
  270. #define ASCII_CHARSET \
  271. "ISO 646-1983//CHARSET International Reference Version (IRV)//ESC 2/5 4/0"
  272.  
  273. static int synrefcharset[256];    /* the syntax reference character set */
  274.  
  275. #define CHAR_NONSGML 01
  276. #define CHAR_SIGNIFICANT 02
  277. #define CHAR_MAGIC 04
  278. #define CHAR_SHUNNED 010
  279.  
  280. static UNCH char_flags[256];
  281. static int done_nonsgml = 0;
  282.  
  283. static UNCH kcharset[] = "CHARSET";
  284. static UNCH kbaseset[] = "BASESET";
  285. static UNCH kdescset[] = "DESCSET";
  286. static UNCH kunused[] = "UNUSED";
  287. static UNCH kcapacity[] = "CAPACITY";
  288. static UNCH kpublic[] = "PUBLIC";
  289. static UNCH ksgmlref[] = "SGMLREF";
  290. static UNCH kscope[] = "SCOPE";
  291. static UNCH kdocument[] = "DOCUMENT";
  292. static UNCH kinstance[] = "INSTANCE";
  293. static UNCH ksyntax[] = "SYNTAX";
  294. static UNCH kswitches[] = "SWITCHES";
  295. static UNCH kfeatures[] = "FEATURES";
  296. static UNCH kminimize[] = "MINIMIZE";
  297. static UNCH kdatatag[] = "DATATAG";
  298. static UNCH komittag[] = "OMITTAG";
  299. static UNCH krank[] = "RANK";
  300. static UNCH kshorttag[] = "SHORTTAG";
  301. static UNCH klink[] = "LINK";
  302. static UNCH ksimple[] = "SIMPLE";
  303. static UNCH kimplicit[] = "IMPLICIT";
  304. static UNCH kexplicit[] = "EXPLICIT";
  305. static UNCH kother[] = "OTHER";
  306. static UNCH kconcur[] = "CONCUR";
  307. static UNCH ksubdoc[] = "SUBDOC";
  308. static UNCH kformal[] = "FORMAL";
  309. static UNCH kyes[] = "YES";
  310. static UNCH kno[] = "NO";
  311. static UNCH kappinfo[] = "APPINFO";
  312. static UNCH knone[] = "NONE";
  313. static UNCH kshunchar[] = "SHUNCHAR";
  314. static UNCH kcontrols[] = "CONTROLS";
  315. static UNCH kfunction[] = "FUNCTION";
  316. static UNCH krs[] = "RS";
  317. static UNCH kre[] = "RE";
  318. static UNCH kspace[] = "SPACE";
  319. static UNCH knaming[] = "NAMING";
  320. static UNCH klcnmstrt[] = "LCNMSTRT";
  321. static UNCH kucnmstrt[] = "UCNMSTRT";
  322. static UNCH klcnmchar[] = "LCNMCHAR";
  323. static UNCH kucnmchar[] = "UCNMCHAR";
  324. static UNCH knamecase[] = "NAMECASE";
  325. static UNCH kdelim[] = "DELIM";
  326. static UNCH kgeneral[] = "GENERAL";
  327. static UNCH kentity[] = "ENTITY";
  328. static UNCH kshortref[] = "SHORTREF";
  329. static UNCH knames[] = "NAMES";
  330. static UNCH kquantity[] = "QUANTITY";
  331.  
  332. #define sderr mderr
  333.  
  334. static UNIV pmaplookup P((struct pmap *, char *));
  335. static UNCH *ltous P((long));
  336. static VOID sdfixcolon P((UNCH *));
  337. static int sdparm P((UNCH *, struct parse *));
  338. static int sdname P((UNCH *, UNCH *));
  339. static int sdckname P((UNCH *, UNCH *));
  340. static int sdversion P((UNCH *));
  341. static int sdcharset P((UNCH *));
  342. static int sdcsdesc P((UNCH *, int *));
  343. static int sdpubcapacity P((UNCH *));
  344. static int sdcapacity P((UNCH *));
  345. static int sdscope P((UNCH *));
  346. static VOID setnonsgml P((void));
  347. static VOID noemptytag P((void));
  348. static int sdpubsyntax P((UNCH *));
  349. static int sdsyntax P((UNCH *));
  350. static int sdxsyntax P((UNCH *));
  351. static int sdtranscharnum P((UNCH *));
  352. static int sdtranschar P((int));
  353. static int sdshunchar P((UNCH *));
  354. static int sdsynref P((UNCH *));
  355. static int sdfunction P((UNCH *));
  356. static int sdnaming P((UNCH *));
  357. static int sddelim P((UNCH *));
  358. static int sdnames P((UNCH *));
  359. static int sdquantity P((UNCH *));
  360. static int sdfeatures P((UNCH *));
  361. static int sdappinfo P((UNCH *));
  362.  
  363. static VOID bufsalloc P((void));
  364. static VOID bufsrealloc P((void));
  365.  
  366. /* Parse the SGML declaration. */
  367.  
  368. VOID sgmldecl()
  369. {
  370.      int i;
  371.      int errsw = 0;
  372.      static int (*section[]) P((UNCH *)) = {
  373.       sdversion,
  374.       sdcharset,
  375.       sdcapacity,
  376.       sdscope,
  377.       sdsyntax,
  378.       sdfeatures,
  379.       sdappinfo,
  380.      };
  381.      /* These are needed if we use mderr. */
  382.      parmno = 0;
  383.      mdname = sgmlkey;
  384.      subdcl = NULL;
  385.      for (i = 0; i < SIZEOF(section); i++)
  386.       if ((*section[i])(tbuf) == FAIL) {
  387.            errsw = 1;
  388.            break;
  389.       }
  390.      bufsrealloc();
  391.      /* Parse the >. */
  392.      if (!errsw)
  393.       sdparm(tbuf, 0);
  394.      /* We must exit if we hit end of document. */
  395.      if (pcbsd.action == EOD_)
  396.       exiterr(161, &pcbsd);
  397.      if (!errsw && pcbsd.action != ESGD)
  398.       sderr(126, (UNCH *)0, (UNCH *)0);
  399. }
  400.  
  401. /* Parse the literal (which should contain the version of the
  402. standard) at the beginning of a SGML declaration. */
  403.  
  404. static int sdversion(tbuf)
  405. UNCH *tbuf;
  406. {
  407.      if (sdparm(tbuf, &pcblitv) != LIT1) {
  408.       sderr(123, (UNCH *)0, (UNCH *)0);
  409.       return FAIL;
  410.      }
  411.      sdfixcolon(tbuf);
  412.      if (ustrcmp(tbuf, standard) != 0)
  413.       sderr(E_BADVERSION, tbuf, standard);
  414.      return SUCCESS;
  415. }
  416.  
  417. /* Parse the CHARSET section. Use one token lookahead. */
  418.  
  419. static int sdcharset(tbuf)
  420. UNCH *tbuf;
  421. {
  422.      int i;
  423.      int status[256];
  424.  
  425.      if (sdname(tbuf, kcharset) == FAIL) return FAIL;
  426.      (void)sdparm(tbuf, 0);
  427.  
  428.      if (sdcsdesc(tbuf, status) == FAIL)
  429.       return FAIL;
  430.  
  431.      for (i = 128; i < 256; i++)
  432.       if (status[i] != UNDESC)
  433.            break;
  434.      if (i >= 256) {
  435.       /* Only a 7-bit character set was described.  Fill it out to 8-bits. */
  436.       for (i = 128; i < 256; i++)
  437.            status[i] = UNUSED;
  438. #if 0
  439.       sderr(E_7BIT, (UNCH *)0, (UNCH *)0);
  440. #endif
  441.      }
  442.      /* Characters that are declared UNUSED in the document character set
  443.     are assigned to non-SGML. */
  444.      for (i = 0; i < 256; i++) {
  445.       if (status[i] == UNDESC) {
  446.            sderr(E_CHARMISSING, ltous((long)i), (UNCH *)0);
  447.            char_flags[i] |= CHAR_NONSGML;
  448.       }
  449.       else if (status[i] == UNUSED)
  450.            char_flags[i] |= CHAR_NONSGML;
  451.      }
  452.      done_nonsgml = 1;
  453.      return SUCCESS;
  454. }
  455.  
  456. /* Parse a character set description.   Uses one character lookahead. */
  457.  
  458. static int sdcsdesc(tbuf, status)
  459. UNCH *tbuf;
  460. int *status;
  461. {
  462.      int i;
  463.      int nsets = 0;
  464.      struct fpi fpi;
  465.  
  466.      for (i = 0; i < 256; i++)
  467.       status[i] = UNDESC;
  468.  
  469.      for (;;) {
  470.       int nchars;
  471.       int *baseset = 0;
  472.  
  473.       if (pcbsd.action != NAS1) {
  474.            if (nsets == 0) {
  475.             sderr(120, (UNCH *)0, (UNCH *)0);
  476.             return FAIL;
  477.            }
  478.            break;
  479.       }
  480.       if (!matches(tbuf, kbaseset)) {
  481.            if (nsets == 0) {
  482.             sderr(118, tbuf+1, kbaseset);
  483.             return FAIL;
  484.            }
  485.            break;
  486.       }
  487.       nsets++;
  488.       MEMZERO((UNIV)&fpi, FPISZ);
  489.       if (sdparm(tbuf, &pcblitv) != LIT1) {
  490.            sderr(123, (UNCH *)0, (UNCH *)0);
  491.            return FAIL;
  492.       }
  493.       fpi.fpipubis = tbuf;
  494.       /* Give a warning if it is not a CHARSET fpi. */
  495.       if (parsefpi(&fpi))
  496.            sderr(E_FORMAL, (UNCH *)0, (UNCH *)0);
  497.       else if (fpi.fpic != FPICHARS)
  498.            sderr(E_BADCLASS, kcharset, (UNCH *)0);
  499.       else {
  500.            fpi.fpipubis[fpi.fpil + fpi.fpill] = '\0';
  501.            baseset = (int *)pmaplookup(charset_map,
  502.                        (char *)fpi.fpipubis + fpi.fpil);
  503.       }
  504.       if (sdname(tbuf, kdescset) == FAIL) return FAIL;
  505.       nchars = 0;
  506.       for (;;) {
  507.            long start, count;
  508.            long basenum;
  509.            if (sdparm(tbuf, 0) != NUM1)
  510.             break;
  511.            start = atol((char *)tbuf + 1);
  512.            if (sdparm(tbuf, 0) != NUM1) {
  513.             sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  514.             return FAIL;
  515.            }
  516.            count = atol((char *)tbuf + 1);
  517.            switch (sdparm(tbuf, &pcblitv)) {
  518.            case NUM1:
  519.             basenum = atol((char *)tbuf + 1);
  520.             break;
  521.            case LIT1:
  522.             basenum = UNKNOWN;
  523.             break;
  524.            case NAS1:
  525.             if (matches(tbuf, kunused)) {
  526.              basenum = UNUSED;
  527.              break;
  528.             }
  529.             /* fall through */
  530.            default:
  531.             sderr(E_CHARDESC, ltous(start), (UNCH *)0);
  532.             return FAIL;
  533.            }
  534.            if (start + count > 256)
  535.             sderr(E_CHARRANGE, (UNCH *)0, (UNCH *)0);
  536.            else {
  537.             int i;
  538.             int lim = (int)start + count;
  539.             for (i = (int)start; i < lim; i++) {
  540.              if (status[i] != UNDESC)
  541.                   sderr(E_CHARDUP, ltous((long)i), (UNCH *)0);
  542.              else if (basenum == UNUSED || basenum == UNKNOWN)
  543.                   status[i] = (int)basenum;
  544.              else if (baseset == 0)
  545.                   status[i] = UNKNOWN_SET;
  546.              else {
  547.                   int n = basenum + (i - start);
  548.                   if (n < 0 || n > 255)
  549.                    sderr(E_CHARRANGE, (UNCH *)0, (UNCH *)0);
  550.                   else if (baseset[n] == UNUSED)
  551.                    sderr(E_BADBASECHAR, ltous((long)n), (UNCH *)0);
  552.                   else
  553.                    status[i] = baseset[n];
  554.              }
  555.             }
  556.            }
  557.            nchars++;
  558.       }
  559.       if (nchars == 0) {
  560.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  561.            return FAIL;
  562.       }
  563.      }
  564.      return SUCCESS;
  565. }
  566.  
  567. /* Parse the CAPACITY section.  Uses one token lookahead. */
  568.  
  569. static int sdcapacity(tbuf)
  570. UNCH *tbuf;
  571. {
  572.      int ncap;
  573.  
  574.      if (sdckname(tbuf, kcapacity) == FAIL)
  575.       return FAIL;
  576.      if (sdparm(tbuf, 0) != NAS1) {
  577.       sderr(120, (UNCH *)0, (UNCH *)0);
  578.       return FAIL;
  579.      }
  580.      if (matches(tbuf, kpublic))
  581.       return sdpubcapacity(tbuf);
  582.      if (!matches(tbuf, ksgmlref)) {
  583.       sderr(E_CAPACITY, tbuf+1, (UNCH *)0);
  584.       return FAIL;
  585.      }
  586.      memcpy((UNIV)sd.capacity, (UNIV)refcapset, sizeof(sd.capacity));
  587.      ncap = 0;
  588.      for (;;) {
  589.       int capno = -1;
  590.       int i;
  591.  
  592.       if (sdparm(tbuf, 0) != NAS1)
  593.            break;
  594.       for (i = 0; i < SIZEOF(captab); i++)
  595.            if (matches(tbuf, captab[i])) {
  596.             capno = i;
  597.             break;
  598.            }
  599.       if (capno < 0)
  600.            break;
  601.       if (sdparm(tbuf, 0) != NUM1) {
  602.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  603.            return FAIL;
  604.       }
  605.       sd.capacity[capno] = atol((char *)tbuf + 1);
  606.       ncap++;
  607.      }
  608.      if (ncap == 0) {
  609.       sderr(E_CAPMISSING, (UNCH *)0, (UNCH *)0);
  610.       return FAIL;
  611.      }
  612.  
  613.      return SUCCESS;
  614. }
  615.  
  616. /* Parse a CAPACITY section that started with PUBLIC.  Must do one
  617. token lookahead, since sdcapacity() also does. */
  618.  
  619. static int sdpubcapacity(tbuf)
  620. UNCH *tbuf;
  621. {
  622.      UNIV ptr;
  623.      if (sdparm(tbuf, &pcblitv) != LIT1) {
  624.       sderr(123, (UNCH *)0, (UNCH *)0);
  625.       return FAIL;
  626.      }
  627.      sdfixcolon(tbuf);
  628.      ptr = pmaplookup(capset_map, (char *)tbuf);
  629.      if (!ptr)
  630.       sderr(E_CAPSET, tbuf, (UNCH *)0);
  631.      else
  632.       memcpy((UNIV)sd.capacity, (UNIV)ptr, sizeof(sd.capacity));
  633.      (void)sdparm(tbuf, 0);
  634.      return SUCCESS;
  635. }
  636.  
  637. /* Parse the SCOPE section. Uses no lookahead. */
  638.  
  639. static int sdscope(tbuf)
  640. UNCH *tbuf;
  641. {
  642.      if (sdckname(tbuf, kscope) == FAIL)
  643.       return FAIL;
  644.      if (sdparm(tbuf, 0) != NAS1) {
  645.       sderr(120, (UNCH *)0, (UNCH *)0);
  646.       return FAIL;
  647.      }
  648.      if (matches(tbuf, kdocument))
  649.       ;
  650.      else if (matches(tbuf, kinstance))
  651.       sderr(E_INSTANCE, (UNCH *)0, (UNCH *)0);
  652.      else {
  653.       sderr(E_SCOPE, tbuf+1, (UNCH *)0);
  654.       return FAIL;
  655.      }
  656.      return SUCCESS;
  657. }
  658.  
  659. /* Parse the SYNTAX section.  Uses one token lookahead. */
  660.  
  661. static int sdsyntax(tbuf)
  662. UNCH *tbuf;
  663. {
  664.      if (sdname(tbuf, ksyntax) == FAIL) return FAIL;
  665.      if (sdparm(tbuf, 0) != NAS1) {
  666.       sderr(120, (UNCH *)0, (UNCH *)0);
  667.       return FAIL;
  668.      }
  669.      if (matches(tbuf, kpublic))
  670.       return sdpubsyntax(tbuf);
  671.      return sdxsyntax(tbuf);
  672. }
  673.  
  674. /* Parse the SYNTAX section which starts with PUBLIC.  Uses one token
  675. lookahead. */
  676.  
  677. static int sdpubsyntax(tbuf)
  678. UNCH *tbuf;
  679. {
  680.      int nswitches;
  681.      if (sdparm(tbuf, &pcblitv) != LIT1)
  682.       return FAIL;
  683.      sdfixcolon(tbuf);
  684.      if (ustrcmp(tbuf, CORE_SYNTAX) == 0)
  685.       sd.shortref = 0;
  686.      else if (ustrcmp(tbuf, REFERENCE_SYNTAX) == 0)
  687.       sd.shortref = 1;
  688.      else
  689.       sderr(E_SYNTAX, tbuf, (UNCH *)0);
  690.      setnonsgml();
  691.      if (sdparm(tbuf, 0) != NAS1)
  692.       return SUCCESS;
  693.      if (!matches(tbuf, kswitches))
  694.       return SUCCESS;
  695.      nswitches = 0;
  696.      for (;;) {
  697.       int errsw = 0;
  698.  
  699.       if (sdparm(tbuf, 0) != NUM1)
  700.            break;
  701.       if (atol((char *)tbuf + 1) > 255) {
  702.            sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  703.            errsw = 1;
  704.       }
  705.       if (sdparm(tbuf, 0) != NUM1) {
  706.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  707.            return FAIL;
  708.       }
  709.       if (!errsw) {
  710.            if (atol((char *)tbuf + 1) > 255)
  711.             sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  712.       }
  713.       nswitches++;
  714.      }
  715.      if (nswitches == 0) {
  716.       sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  717.       return FAIL;
  718.      }
  719.      sderr(E_SWITCHES, (UNCH *)0, (UNCH *)0);
  720.      return SUCCESS;
  721. }
  722.  
  723. /* Parse an explicit concrete syntax. Uses one token lookahead. */
  724.  
  725. static
  726. int sdxsyntax(tbuf)
  727. UNCH *tbuf;
  728. {
  729.      static int (*section[]) P((UNCH *)) = {
  730.       sdshunchar,
  731.       sdsynref,
  732.       sdfunction,
  733.       sdnaming,
  734.       sddelim,
  735.       sdnames,
  736.       sdquantity,
  737.      };
  738.      int i;
  739.  
  740.      for (i = 0; i < SIZEOF(section); i++)
  741.       if ((*section[i])(tbuf) == FAIL)
  742.            return FAIL;
  743.      return SUCCESS;
  744. }
  745.  
  746. /* Parse the SHUNCHAR section. Uses one token lookahead. */
  747.  
  748. static
  749. int sdshunchar(tbuf)
  750. UNCH *tbuf;
  751. {
  752.      int i;
  753.      for (i = 0; i < 256; i++)
  754.       char_flags[i] &= ~CHAR_SHUNNED;
  755.  
  756.      if (sdckname(tbuf, kshunchar) == FAIL)
  757.       return FAIL;
  758.  
  759.      if (sdparm(tbuf, 0) == NAS1) {
  760.       if (matches(tbuf, knone)) {
  761.            (void)sdparm(tbuf, 0);
  762.            setnonsgml();
  763.            return SUCCESS;
  764.       }
  765.       if (matches(tbuf, kcontrols)) {
  766.            for (i = 0; i < 256; i++)
  767.             if (ISASCII(i) && iscntrl(i))
  768.              char_flags[i] |= CHAR_SHUNNED;
  769.            if (sdparm(tbuf, 0) != NUM1) {
  770.             setnonsgml();
  771.             return SUCCESS;
  772.            }
  773.       }
  774.      }
  775.      if (pcbsd.action != NUM1) {
  776.       sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  777.       return FAIL;
  778.      }
  779.      do {
  780.       long n = atol((char *)tbuf + 1);
  781.       if (n > 255)
  782.            sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  783.       else
  784.            char_flags[(int)n] |= CHAR_SHUNNED;
  785.      } while (sdparm(tbuf, 0) == NUM1);
  786.      setnonsgml();
  787.      return SUCCESS;
  788. }
  789.  
  790. /* Parse the syntax reference character set. Uses one token lookahead. */
  791.  
  792. static
  793. int sdsynref(tbuf)
  794. UNCH *tbuf;
  795. {
  796.      return sdcsdesc(tbuf, synrefcharset);
  797. }
  798.  
  799. /* Translate a character number from the syntax reference character set
  800. to the system character set. If it can't be done, give an error message
  801. and return -1. */
  802.  
  803. static
  804. int sdtranscharnum(tbuf)
  805. UNCH *tbuf;
  806. {
  807.      long n = atol((char *)tbuf + 1);
  808.      if (n > 255) {
  809.       sderr(E_CHARNUM, (UNCH *)0, (UNCH *)0);
  810.       return -1;
  811.      }
  812.      return sdtranschar((int)n);
  813. }
  814.  
  815.  
  816. static
  817. int sdtranschar(n)
  818. int n;
  819. {
  820.      int ch = synrefcharset[n];
  821.      if (ch >= 0)
  822.       return ch;
  823.      switch (ch) {
  824.      case UNUSED:
  825.       sderr(E_SYNREFUNUSED, ltous(n), (UNCH *)0);
  826.       break;
  827.      case UNDESC:
  828.       sderr(E_SYNREFUNDESC, ltous(n), (UNCH *)0);
  829.       break;
  830.      case UNKNOWN:
  831.       sderr(E_SYNREFUNKNOWN, ltous(n), (UNCH *)0);
  832.       break;
  833.      case UNKNOWN_SET:
  834.       sderr(E_SYNREFUNKNOWNSET, ltous(n), (UNCH *)0);
  835.       break;
  836.      default:
  837.       abort();
  838.      }
  839.      return -1;
  840. }
  841.  
  842.  
  843. /* Parse the function section. Uses two tokens lookahead. "NAMING"
  844. could be a function name. */
  845.  
  846. static
  847. int sdfunction(tbuf)
  848. UNCH *tbuf;
  849. {
  850.      static UNCH *fun[] = { kre, krs, kspace };
  851.      static int funval[] = { RECHAR, RSCHAR, ' ' };
  852.      int i;
  853.      int had_tab = 0;
  854.      int changed = 0;        /* attempted to change reference syntax */
  855.  
  856.      if (sdckname(tbuf, kfunction) == FAIL)
  857.       return FAIL;
  858.      for (i = 0; i < SIZEOF(fun); i++) {
  859.       int ch;
  860.       if (sdname(tbuf, fun[i]) == FAIL)
  861.            return FAIL;
  862.       if (sdparm(tbuf, 0) != NUM1) {
  863.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  864.            return FAIL;
  865.       }
  866.       ch = sdtranscharnum(tbuf);
  867.       if (ch >= 0 && ch != funval[i])
  868.            changed = 1;
  869.      }
  870.      for (;;) {
  871.       int tabsw = 0;
  872.       int namingsw = 0;
  873.       if (sdparm(tbuf, 0) != NAS1) {
  874.            sderr(120, (UNCH *)0, (UNCH *)0);
  875.            return FAIL;
  876.       }
  877.       if (matches(tbuf, (UNCH *)"TAB")) {
  878.            tabsw = 1;
  879.            if (had_tab)
  880.             sderr(E_FUNDUP, (UNCH *)0, (UNCH *)0);
  881.       }
  882.       else {
  883.            for (i = 0; i < SIZEOF(fun); i++)
  884.             if (matches(tbuf, fun[i]))
  885.              sderr(E_BADFUN, fun[i], (UNCH *)0);
  886.            if (matches(tbuf, knaming))
  887.             namingsw = 1;
  888.            else
  889.             changed = 1;
  890.       }
  891.       if (sdparm(tbuf, 0) != NAS1) {
  892.            sderr(120, (UNCH *)0, (UNCH *)0);
  893.            return FAIL;
  894.       }
  895.       if (namingsw) {
  896.            if (matches(tbuf, klcnmstrt))
  897.             break;
  898.            changed = 1;
  899.       }
  900.       if (sdparm(tbuf, 0) != NUM1) {
  901.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  902.            return FAIL;
  903.       }
  904.       if (tabsw && !had_tab) {
  905.            int ch = sdtranscharnum(tbuf);
  906.            if (ch >= 0 && ch != TABCHAR)
  907.             changed = 1;
  908.            had_tab = 1;
  909.       }
  910.  
  911.      }
  912.      if (!had_tab)
  913.       changed = 1;
  914.      if (changed)
  915.       sderr(E_FUNCHAR, (UNCH *)0, (UNCH *)0);
  916.      return SUCCESS;
  917. }
  918.  
  919. /* Parse the NAMING section.  Uses no lookahead. */
  920.  
  921. static
  922. int sdnaming(tbuf)
  923. UNCH *tbuf;
  924. {
  925.      int i;
  926.      int bad = 0;
  927.      static UNCH *classes[] = { klcnmstrt, kucnmstrt, klcnmchar, kucnmchar };
  928.      static UNCH *types[] = { kgeneral, kentity };
  929.      char v[2][2];
  930.  
  931.      MEMZERO(v, sizeof(v));
  932.  
  933.      for (i = 0; i < SIZEOF(classes); i++) {
  934.       int n;
  935.       if (sdckname(tbuf, classes[i]) == FAIL)
  936.            return FAIL;
  937.       n = 1;
  938.       while (sdparm(tbuf, &pcblitp) == LIT1)
  939.            if (!bad) {
  940.             if (i < 2) {
  941.              if (*tbuf)
  942.                   bad = 1;
  943.             }
  944.             else {
  945.              UNCH *s;
  946.              for (s = tbuf; *s; s++) {
  947.                   int ch = sdtranschar(*s);
  948.                   if (ch < 0)
  949.                    bad = 1;
  950.                   if (ch != '-' && ch != '.')
  951.                    bad = 1;
  952.                   v[i != 2][ch == '.'] = n++;
  953.              }
  954.                   
  955.             }
  956.            }
  957.       
  958.      }
  959.      if (!bad) {
  960.       for (i = 0; i < 2; i++) {
  961.            int j;
  962.            for (j = 0; j < 2; j++)
  963.             if ((v[i][j] != 1 && v[i][j] != 2) || v[0][j] != v[1][j])
  964.              bad = 1;
  965.       }
  966.      }
  967.      if (bad)
  968.       sderr(E_NAMING, (UNCH *)0, (UNCH *)0);
  969.  
  970.      if (sdckname(tbuf, knamecase) == FAIL)
  971.       return FAIL;
  972.      for (i = 0; i < SIZEOF(types); ++i) {
  973.       if (sdname(tbuf, types[i]) == FAIL)
  974.            return FAIL;
  975.       if (sdparm(tbuf, 0) != NAS1) {
  976.            sderr(120, (UNCH *)0, (UNCH *)0);
  977.            return FAIL;
  978.       }
  979.       if (matches(tbuf, kyes))
  980.            sd.namecase[i] = 1;
  981.       else if (matches(tbuf, kno))
  982.            sd.namecase[i] = 0;
  983.       else {
  984.            sderr(E_YESNO, tbuf+1, (UNCH *)0);
  985.            return FAIL;
  986.       }
  987.      }
  988.      return SUCCESS;
  989. }
  990.  
  991. /* Parse the DELIM section. Uses one token lookahead. */
  992.  
  993. static
  994. int sddelim(tbuf)
  995. UNCH *tbuf;
  996. {
  997.      int changed = 0;
  998.      if (sdname(tbuf, kdelim) == FAIL
  999.      || sdname(tbuf, kgeneral) == FAIL
  1000.      || sdname(tbuf, ksgmlref) == FAIL)
  1001.       return FAIL;
  1002.      for (;;) {
  1003.       if (sdparm(tbuf, 0) != NAS1) {
  1004.            sderr(120, (UNCH *)0, (UNCH *)0);
  1005.            return FAIL;
  1006.       }
  1007.       if (matches(tbuf, kshortref))
  1008.            break;
  1009.       if (sdparm(tbuf, &pcblitp) != LIT1) {
  1010.            sderr(123, (UNCH *)0, (UNCH *)0);
  1011.            return FAIL;
  1012.       }
  1013.       changed = 1;
  1014.      }
  1015.      if (changed) {
  1016.       sderr(E_GENDELIM, (UNCH *)0,(UNCH *)0);
  1017.       changed = 0;
  1018.      }
  1019.      if (sdparm(tbuf, 0) != NAS1) {
  1020.       sderr(120, (UNCH *)0, (UNCH *)0);
  1021.       return FAIL;
  1022.      }
  1023.      if (matches(tbuf, ksgmlref))
  1024.       sd.shortref = 1;
  1025.      else if (matches(tbuf, knone))
  1026.       sd.shortref = 0;
  1027.      else {
  1028.       sderr(118, tbuf+1, ksgmlref);    /* probably they forgot SGMLREF */
  1029.       return FAIL;
  1030.      }
  1031.      while (sdparm(tbuf, &pcblitp) == LIT1)
  1032.       changed = 1;
  1033.      if (changed)
  1034.       sderr(E_SRDELIM, (UNCH *)0, (UNCH *)0);
  1035.      return SUCCESS;
  1036. }
  1037.  
  1038. /* Parse the NAMES section. Uses one token lookahead. */
  1039.  
  1040. static
  1041. int sdnames(tbuf)
  1042. UNCH *tbuf;
  1043. {
  1044.      int i;
  1045.      if (sdckname(tbuf, knames) == FAIL)
  1046.       return FAIL;
  1047.      if (sdname(tbuf, ksgmlref) == FAIL)
  1048.       return FAIL;
  1049.  
  1050.      while (sdparm(tbuf, 0) == NAS1) {
  1051.       int j;
  1052.       if (matches(tbuf, kquantity))
  1053.            break;
  1054.       for (i = 0; i < NKEYS; i++)
  1055.            if (matches(tbuf, key[i]))
  1056.             break;
  1057.       if (i >= NKEYS)
  1058.            sderr(E_BADKEY, tbuf+1, (UNCH *)0);
  1059.       if (sdparm(tbuf, &pcblitp) != NAS1) {
  1060.            sderr(120, (UNCH *)0, (UNCH *)0);
  1061.            return FAIL;
  1062.       }
  1063.       if (!newkey) {
  1064.            newkey = (UNCH (*)[REFNAMELEN+1])rmalloc((REFNAMELEN+1)*NKEYS);
  1065.            MEMZERO((UNIV)newkey, (REFNAMELEN+1)*NKEYS);
  1066.       }
  1067.       for (j = 0; j < NKEYS; j++) {
  1068.            if (matches(tbuf, key[j])) {
  1069.             sderr(E_REFNAME, tbuf + 1, (UNCH *)0);
  1070.             break;
  1071.            }
  1072.            if (matches(tbuf, newkey[j])) {
  1073.             sderr(E_DUPNAME, tbuf + 1, (UNCH *)0);
  1074.             break;
  1075.            }
  1076.       }
  1077.       if (j >= NKEYS)
  1078.            ustrcpy(newkey[i], tbuf + 1);
  1079.      }
  1080.      /* Now install the new keys. */
  1081.      if (newkey) {
  1082.       for (i = 0; i < NKEYS; i++)
  1083.            if (newkey[i][0] != '\0') {
  1084.             UNCH temp[REFNAMELEN];
  1085.             
  1086.             ustrcpy(temp, key[i]);
  1087.             ustrcpy(key[i], newkey[i]);
  1088.             ustrcpy(newkey[i], temp);
  1089.            }
  1090.      }
  1091.      return SUCCESS;
  1092. }
  1093.  
  1094. /* Parse the QUANTITY section. Uses one token lookahead. */
  1095.  
  1096. static int sdquantity(tbuf)
  1097. UNCH *tbuf;
  1098. {
  1099.      int quantity[NQUANTITY];
  1100.      int i;
  1101.  
  1102.      for (i = 0; i < NQUANTITY; i++)
  1103.       quantity[i] = -1;
  1104.      if (sdckname(tbuf, kquantity) == FAIL)
  1105.       return FAIL;
  1106.      if (sdname(tbuf, ksgmlref) == FAIL)
  1107.       return FAIL;
  1108.      while (sdparm(tbuf, 0) == NAS1 && !matches(tbuf, kfeatures)) {
  1109.       long n;
  1110.       for (i = 0; i < SIZEOF(quantity_names); i++)
  1111.            if (matches(tbuf, quantity_names[i]))
  1112.             break;
  1113.       if (i >= SIZEOF(quantity_names)) {
  1114.            sderr(E_BADQUANTITY, tbuf + 1, (UNCH *)0);
  1115.            return FAIL;
  1116.       }
  1117.       if (sdparm(tbuf, 0) != NUM1) {
  1118.            sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  1119.            return FAIL;
  1120.       }
  1121.       n = atol((char *)tbuf + 1);
  1122.       if (n < sd.quantity[i])
  1123.            sderr(E_QUANTITY, (UNCH *)quantity_names[i],
  1124.              ltous((long)sd.quantity[i]));
  1125.       else if (n > max_quantity[i]) {
  1126.            sderr(E_QTOOBIG, (UNCH *)quantity_names[i],
  1127.              ltous((long)max_quantity[i]));
  1128.            quantity[i] = max_quantity[i];
  1129.       }
  1130.       else
  1131.            quantity[i] = (int)n;
  1132.      }
  1133.      for (i = 0; i < NQUANTITY; i++)
  1134.       if (quantity[i] > 0) {
  1135.            sd.quantity[i] = quantity[i];
  1136.            if (!quantity_changed)
  1137.             quantity_changed = (char *)rmalloc(NQUANTITY);
  1138.            quantity_changed[i] = 1;
  1139.       }
  1140.      return SUCCESS;
  1141. }
  1142.  
  1143. /* Parse the FEATURES section.  Uses no lookahead. */
  1144.  
  1145. static int sdfeatures(tbuf)
  1146. UNCH *tbuf;
  1147. {
  1148.      static struct  {
  1149.       UNCH *name;
  1150.       UNCH argtype;  /* 0 = no argument, 1 = boolean, 2 = numeric */
  1151.       UNIV valp;     /* UNCH * if boolean, long * if numeric. */
  1152.      } features[] = {
  1153.       kminimize, 0, 0,
  1154.       kdatatag, 1, 0,
  1155.       komittag, 1, (UNIV)&sd.omittag,
  1156.       krank, 1, 0,
  1157.       kshorttag, 1, (UNIV)&sd.shorttag,
  1158.       klink, 0, 0,
  1159.       ksimple, 2, 0,
  1160.       kimplicit, 1, 0,
  1161.       kexplicit, 2, 0,
  1162.       kother, 0, 0,
  1163.       kconcur, 2, 0,
  1164.       ksubdoc, 2, (UNIV)&sd.subdoc,
  1165.       kformal, 1, (UNIV)&sd.formal,
  1166.      };
  1167.  
  1168.      int i;
  1169.  
  1170.      if (sdckname(tbuf, kfeatures) == FAIL)
  1171.       return FAIL;
  1172.      for (i = 0; i < SIZEOF(features); i++) {
  1173.       if (sdname(tbuf, features[i].name) == FAIL) return FAIL;
  1174.       if (features[i].argtype > 0) {
  1175.            long n;
  1176.            if (sdparm(tbuf, 0) != NAS1) {
  1177.             sderr(120, (UNCH *)0, (UNCH *)0);
  1178.             return FAIL;
  1179.            }
  1180.            if (matches(tbuf, kyes)) {
  1181.             if (features[i].argtype > 1) {
  1182.              if (sdparm(tbuf, 0) != NUM1) {
  1183.                   sderr(E_XNUM, (UNCH *)0, (UNCH *)0);
  1184.                   return FAIL;
  1185.              }
  1186.              n = atol((char *)tbuf + 1);
  1187.              if (n == 0)
  1188.                   sderr(E_ZEROFEATURE, features[i].name, (UNCH *)0);
  1189.             }
  1190.             else
  1191.              n = 1;
  1192.            }
  1193.            else if (matches(tbuf, kno))
  1194.             n = 0;
  1195.            else {
  1196.             sderr(E_YESNO, tbuf+1, (UNCH *)0);
  1197.             return FAIL;
  1198.            }
  1199.            if (features[i].valp == 0) {
  1200.             if (n > 0)
  1201.              sderr(E_NOTSUPPORTED, features[i].name,
  1202.                   (UNCH *)0);
  1203.            }
  1204.            else if (features[i].argtype > 1)
  1205.             *(long *)features[i].valp = n;
  1206.            else
  1207.             *(UNCH *)features[i].valp = (UNCH)n;
  1208.       }
  1209.      }
  1210.      if (!sd.shorttag)
  1211.       noemptytag();
  1212.      return SUCCESS;
  1213. }
  1214.  
  1215. /* Parse the APPINFO section.  Uses no lookahead. */
  1216.  
  1217. static int sdappinfo(tbuf)
  1218. UNCH *tbuf;
  1219. {
  1220.      if (sdname(tbuf, kappinfo) == FAIL) return FAIL;
  1221.      switch (sdparm(tbuf, &pcblitv)) {
  1222.      case LIT1:
  1223.       appinfosw = 1;
  1224.       ustrcpy(appinfo, tbuf);
  1225.       break;
  1226.      case NAS1:
  1227.       if (matches(tbuf, knone))
  1228.            break;
  1229.       sderr(118, tbuf+1, knone);
  1230.       return FAIL;
  1231.      default:
  1232.       sderr(E_XNMLIT, knone, (UNCH *)0);
  1233.       return FAIL;
  1234.      }
  1235.      return SUCCESS;
  1236. }
  1237.  
  1238. /* Change a prefix of ISO 8879:1986 to ISO 8879-1986.  Goldfarb uses
  1239. the former (because the draft revised SGML standard uses that), but
  1240. the current standard uses the latter.  Erik says it was changed by the
  1241. amendment.  Check this. */
  1242.  
  1243. static VOID sdfixcolon(tbuf)
  1244. UNCH *tbuf;
  1245. {
  1246.      if (strncmp((char *)tbuf, "ISO 8879:1986", 13) == 0) {
  1247. #if 0
  1248.       sderr(E_COLON, (UNCH *)0, (UNCH *)0);
  1249. #endif
  1250.       tbuf[8] = '-';
  1251.      }
  1252. }
  1253.  
  1254. static int sdname(tbuf, key)
  1255. UNCH *tbuf;
  1256. UNCH *key;
  1257. {
  1258.      if (sdparm(tbuf, 0) != NAS1) {
  1259.       sderr(120, (UNCH *)0, (UNCH *)0);
  1260.       return FAIL;
  1261.      }
  1262.      if (!matches(tbuf, key)) {
  1263.       sderr(118, tbuf+1, key);
  1264.       return FAIL;
  1265.      }
  1266.      return SUCCESS;
  1267. }
  1268.  
  1269. static int sdckname(tbuf, key)
  1270. UNCH *tbuf;
  1271. UNCH *key;
  1272. {
  1273.      if (pcbsd.action != NAS1) {
  1274.       sderr(120, (UNCH *)0, (UNCH *)0);
  1275.       return FAIL;
  1276.      }
  1277.      if (!matches(tbuf, key)) {
  1278.       sderr(118, tbuf+1, key);
  1279.       return FAIL;
  1280.      }
  1281.      return SUCCESS;
  1282. }
  1283.  
  1284. /* Parse a SGML declaration parameter.  If lpcb is NULL, pt must be
  1285. REFNAMELEN+2 characters long, otherwise at least LITLEN+2 characters
  1286. long. LPCB should be NULL if a literal is not allowed. */
  1287.  
  1288. static int sdparm(pt, lpcb)
  1289. UNCH *pt;            /* Token buffer. */
  1290. struct parse *lpcb;        /* PCB for literal parse. */
  1291. {
  1292.      for (;;) {
  1293.       parse(&pcbsd);
  1294.       if (pcbsd.action != ISIG)
  1295.            break;
  1296.       sderr(E_SIGNIFICANT, (UNCH *)0, (UNCH *)0);
  1297.      }
  1298.      ++parmno;
  1299.      switch (pcbsd.action) {
  1300.      case LIT1:
  1301.       if (!lpcb) {
  1302.            sderr(E_BADLIT, (UNCH *)0, (UNCH *)0);
  1303.            REPEATCC;
  1304.            return pcbsd.action = INV_;
  1305.       }
  1306.       parselit(pt, lpcb, REFLITLEN, lex.d.lit);
  1307.       return pcbsd.action;
  1308.      case LIT2:
  1309.       if (!lpcb) {
  1310.            sderr(E_BADLIT, (UNCH *)0, (UNCH *)0);
  1311.            REPEATCC;
  1312.            return pcbsd.action = INV_;
  1313.       }
  1314.       parselit(pt, lpcb, REFLITLEN, lex.d.lita);
  1315.       return pcbsd.action = LIT1;
  1316.      case NAS1:
  1317.       parsenm(pt, 1);
  1318.       return pcbsd.action;
  1319.      case NUM1:
  1320.       parsetkn(pt, NU, REFNAMELEN);
  1321.       return pcbsd.action;
  1322.      }
  1323.      return pcbsd.action;
  1324. }
  1325.  
  1326. VOID sdinit()
  1327. {
  1328.      int i;
  1329.      /* Shunned character numbers in the reference concrete syntax. */
  1330.      static UNCH refshun[] = { 
  1331.       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
  1332.       19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127, 255
  1333.       };
  1334.      UNCH **p;
  1335.      /* A character is magic if it is a non-SGML character used for
  1336.      some internal purpose in the parser. */
  1337.      char_flags[EOS] |= CHAR_MAGIC;
  1338.      char_flags[BADCHAR] |= CHAR_MAGIC;
  1339.      char_flags[EOBCHAR] |= CHAR_MAGIC;
  1340.      char_flags[EOFCHAR] |= CHAR_MAGIC;
  1341.      char_flags[GENRECHAR] |= CHAR_MAGIC;
  1342.      char_flags[sw.delnonch] |= CHAR_MAGIC;
  1343.      char_flags[sw.delcdata] |= CHAR_MAGIC;
  1344.      char_flags[sw.delsdata] |= CHAR_MAGIC;
  1345.  
  1346.      /* Figure out the significant SGML characters. */
  1347.      for (p = lextabs; *p; p++) {
  1348.       UNCH datclass = (*p)[CANON_DATACHAR];
  1349.       UNCH nonclass = (*p)[CANON_NONSGML];
  1350.       for (i = 0; i < 256; i++)
  1351.            if (!(char_flags[i] & CHAR_MAGIC)
  1352.            && (*p)[i] != datclass && (*p)[i] != nonclass)
  1353.             char_flags[i] |= CHAR_SIGNIFICANT;
  1354.      }
  1355.      for (i = 0; i < SIZEOF(refshun); i++)
  1356.       char_flags[refshun[i]] |= CHAR_SHUNNED;
  1357.      for (i = 0; i < 256; i++)
  1358.       if (ISASCII(i) && iscntrl(i))
  1359.            char_flags[i] |= CHAR_SHUNNED;
  1360.      bufsalloc();
  1361. }
  1362.  
  1363.  
  1364. static
  1365. VOID bufsalloc()
  1366. {
  1367.      scbs = (struct source *)rmalloc((REFENTLVL+1)*sizeof(struct source));
  1368.      tbuf = (UNCH *)rmalloc(REFATTSPLEN+REFLITLEN+1);
  1369. }
  1370.  
  1371. static
  1372. VOID bufsrealloc()
  1373. {
  1374.      UNS size;
  1375.      
  1376.      if (ENTLVL != REFENTLVL)
  1377.       scbs = (struct source *)rrealloc((UNIV)scbs,
  1378.                        (ENTLVL+1)*sizeof(struct source));
  1379.      /* Calculate the size for tbuf. */
  1380.      size = LITLEN + ATTSPLEN;
  1381.      if (PILEN > size)
  1382.       size = PILEN;
  1383.      if (BSEQLEN > size)
  1384.       size = BSEQLEN;
  1385.      if (size != REFATTSPLEN + REFLITLEN)
  1386.       tbuf = (UNCH *)rrealloc((UNIV)tbuf, size + 1);
  1387. }
  1388.  
  1389. /* Check that the non-SGML characters are compatible with the concrete
  1390. syntax and munge the lexical tables accordingly.  If IMPLIED is
  1391. non-zero, then the SGML declaration was implied; in this case, don't
  1392. give error messages about shunned characters not being declared
  1393. non-SGML. */
  1394.  
  1395. static VOID setnonsgml()
  1396. {
  1397.      int i;
  1398.      UNCH **p;
  1399.      
  1400.      for (i = 0; i < 256; i++)
  1401.       if (char_flags[i] & CHAR_SIGNIFICANT) {
  1402.            /* Significant SGML characters musn't be non-SGML. */
  1403.            if (char_flags[i] & CHAR_NONSGML) {
  1404.             UNCH buf[2];
  1405.             buf[0] = i;
  1406.             buf[1] = '\0';
  1407.             sderr(E_NONSGML, buf, (UNCH *)0);
  1408.             char_flags[i] &= ~CHAR_NONSGML;
  1409.            }
  1410.       }
  1411.       else {
  1412.            /* Shunned characters that are not significant SGML characters
  1413.           must be non-SGML. */
  1414.            if ((char_flags[i] & (CHAR_SHUNNED | CHAR_NONSGML))
  1415.            == CHAR_SHUNNED) {
  1416.            sderr(E_SHUNNED, ltous((long)i), (UNCH *)0);
  1417.            char_flags[i] |= CHAR_NONSGML;
  1418.            }
  1419.       }
  1420.  
  1421.      
  1422.      /* Now munge the lexical tables. */
  1423.       
  1424.      for (p = lextabs; *p; p++) {
  1425.       UNCH nonclass = (*p)[CANON_NONSGML];
  1426.       UNCH datclass = (*p)[CANON_DATACHAR];
  1427.       for (i = 0; i < 256; i++) {
  1428.            if (char_flags[i] & CHAR_NONSGML) {
  1429.             /* We already know that it's not significant. */
  1430.             if (!(char_flags[i] & CHAR_MAGIC))
  1431.              (*p)[i] = nonclass;
  1432.            }
  1433.            else {
  1434.             if (char_flags[i] & CHAR_MAGIC) {
  1435.              sderr(E_MUSTBENON, ltous((long)i), (UNCH *)0);
  1436.             }
  1437.             else if (!(char_flags[i] & CHAR_SIGNIFICANT))
  1438.              (*p)[i] = datclass;
  1439.            }
  1440.       }
  1441.      }
  1442.      
  1443. }
  1444.  
  1445. /* Munge parse tables so that empty start and end tags are not recognized. */
  1446.  
  1447. static VOID noemptytag()
  1448. {
  1449.      static struct parse *pcbs[] = { &pcbconm, &pcbcone, &pcbconr, &pcbconc };
  1450.      int i;
  1451.      
  1452.      for (i = 0; i < SIZEOF(pcbs); i++) {
  1453.       int maxclass, maxstate;
  1454.       int j, k, act;
  1455.       UNCH *plex = pcbs[i]->plex;
  1456.       UNCH **ptab = pcbs[i]->ptab;
  1457.  
  1458.       /* Figure out the maximum lexical class. */
  1459.       maxclass = 0;
  1460.       for (j = 0; j < 256; j++)
  1461.            if (plex[j] > maxclass)
  1462.             maxclass = plex[j];
  1463.  
  1464.       /* Now figure out the maximum state number and at the same time
  1465.          change actions. */
  1466.  
  1467.       maxstate = 0;
  1468.  
  1469.       for (j = 0; j <= maxstate; j += 2) {
  1470.            for (k = 0; k <= maxclass; k++)
  1471.             if (ptab[j][k] > maxstate)
  1472.              maxstate = ptab[j][k];
  1473.            /* If the '>' class has an empty start or end tag action,
  1474.           change it to the action that the NMC class has. */
  1475.            act = ptab[j + 1][plex['>']];
  1476.            if (act == NET_ || act == NST_)
  1477.             ptab[j + 1][plex['>']] = ptab[j + 1][plex['_']];
  1478.       }
  1479.      }
  1480. }
  1481.  
  1482. /* Lookup the value of the entry in pmap PTR whose key is KEY. */
  1483.  
  1484. static UNIV pmaplookup(ptr, key)
  1485. struct pmap *ptr;
  1486. char *key;
  1487. {
  1488.      for (; ptr->name; ptr++)
  1489.       if (strcmp(key, ptr->name) == 0)
  1490.            return ptr->value;
  1491.      return 0;
  1492. }
  1493.  
  1494. /* Return an ASCII representation of N. */
  1495.  
  1496. static UNCH *ltous(n)
  1497. long n;
  1498. {
  1499.      static char buf[sizeof(long)*3 + 2];
  1500.      sprintf(buf, "%ld", n);
  1501.      return (UNCH *)buf;
  1502. }
  1503.  
  1504. VOID sgmlwrsd(fp)
  1505. FILE *fp;
  1506. {
  1507.      int i;
  1508.      int changed;
  1509.      fprintf(fp, "<!SGML \"%s\"\n", standard);
  1510.      fprintf(fp, "CHARSET\nBASESET \"%s\"\nDESCSET\n", DUMMY_CHARSET);
  1511.      
  1512.      if (!done_nonsgml) {
  1513.       done_nonsgml = 1;
  1514.       for (i = 0; i < 256; i++)
  1515.            if ((char_flags[i] & (CHAR_SIGNIFICANT | CHAR_SHUNNED))
  1516.            == CHAR_SHUNNED)
  1517.                 char_flags[i] |= CHAR_NONSGML;
  1518.      }
  1519.      i = 0;
  1520.      while (i < 256) {
  1521.       int j;
  1522.       for (j = i + 1; j < 256; j++)
  1523.            if ((char_flags[j] & CHAR_NONSGML)
  1524.            != (char_flags[i] & CHAR_NONSGML))
  1525.             break;
  1526.       if (char_flags[i] & CHAR_NONSGML)
  1527.            fprintf(fp, "%d %d UNUSED\n", i, j - i);
  1528.       else
  1529.            fprintf(fp, "%d %d %d\n", i, j - i, i);
  1530.       i = j;
  1531.      }
  1532.      fprintf(fp, "CAPACITY\n");
  1533.      changed = 0;
  1534.      for (i = 0; i < NCAPACITY; i++)
  1535.       if (refcapset[i] != sd.capacity[i]) {
  1536.            if (!changed) {
  1537.             fprintf(fp, "SGMLREF\n");
  1538.             changed = 1;
  1539.            }
  1540.            fprintf(fp, "%s %ld\n", captab[i], sd.capacity[i]);
  1541.       }
  1542.      if (!changed)
  1543.       fprintf(fp, "PUBLIC \"%s\"\n", capset_map[0].name);
  1544.      fprintf(fp, "SCOPE DOCUMENT\n");
  1545.      
  1546.      fprintf(fp, "SYNTAX\nSHUNCHAR");
  1547.      for (i = 0; i < 256; i++)
  1548.       if (char_flags[i] & CHAR_SHUNNED)
  1549.            fprintf(fp, " %d", i);
  1550.      fprintf(fp, "\n");
  1551.      fprintf(fp, "BASESET \"%s\"\nDESCSET 0 128 0\n", ASCII_CHARSET);
  1552.      fprintf(fp, "FUNCTION\nRE 13\nRS 10\nSPACE 32\nTAB SEPCHAR 9\n");
  1553.      fprintf(fp, "NAMING\nLCNMSTRT \"\"\nUCNMSTRT \"\"\n\
  1554. LCNMCHAR \"-.\"\nUCNMCHAR \"-.\"\n");
  1555.      fprintf(fp, "NAMECASE\nGENERAL %s\nENTITY %s\n",
  1556.          sd.namecase[0] ? "YES" : "NO",
  1557.          sd.namecase[1] ? "YES" : "NO");
  1558.      fprintf(fp, "DELIM\nGENERAL SGMLREF\nSHORTREF %s\n",
  1559.          sd.shortref ? "SGMLREF" : "NONE");
  1560.      fprintf(fp, "NAMES SGMLREF\n");
  1561.      if (newkey) {
  1562.       /* The reference key was saved in newkey. */
  1563.       for (i = 0; i < NKEYS; i++)
  1564.            if (newkey[i][0])
  1565.             fprintf(fp, "%s %s\n", newkey[i], key[i]);
  1566.      }
  1567.      fprintf(fp, "QUANTITY SGMLREF\n");
  1568.      if (quantity_changed)
  1569.       for (i = 0; i < NQUANTITY; i++)
  1570.            if (quantity_changed[i])
  1571.             fprintf(fp, "%s %d\n", quantity_names[i], sd.quantity[i]);
  1572.      fprintf(fp,
  1573.          "FEATURES\nMINIMIZE\nDATATAG NO OMITTAG %s RANK NO SHORTTAG %s\n",
  1574.          sd.omittag ? "YES" : "NO",
  1575.          sd.shorttag ? "YES" : "NO");
  1576.      fprintf(fp, "LINK SIMPLE NO IMPLICIT NO EXPLICIT NO\n");
  1577.      fprintf(fp, "OTHER CONCUR NO ");
  1578.      if (sd.subdoc > 0)
  1579.       fprintf(fp, "SUBDOC YES %ld ", sd.subdoc);
  1580.      else
  1581.       fprintf(fp, "SUBDOC NO ");
  1582.      fprintf(fp, "FORMAL %s\n", sd.formal ? "YES" : "NO");
  1583.      if (appinfo[0])
  1584.       fprintf(fp, "APPINFO \"%s\"", appinfo);
  1585.      else
  1586.       fprintf(fp, "APPINFO NONE");
  1587.      fprintf(fp, ">\n");
  1588. }
  1589.  
  1590. UNCH *sgmlappinfo()
  1591. {
  1592.      if (appinfosw)
  1593.       return appinfo;
  1594.      else
  1595.       return 0;
  1596. }
  1597.  
  1598. /*
  1599. Local Variables:
  1600. c-indent-level: 5
  1601. c-continued-statement-offset: 5
  1602. c-brace-offset: -5
  1603. c-argdecl-indent: 0
  1604. c-label-offset: -5
  1605. End:
  1606. */
  1607.